package com.maimao.auth.imageCode.mobile;

import com.maimao.auth.model.SysAuthUser;
import com.maimao.auth.service.BaseUserDetailsService;
import com.maimao.core.constant.RedisKeys;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;

/**
 * @author MaoLin Wang
 * @date 2020/12/14 3:29 下午
 */
public class MobilePwdCodeAuthenticationProvider implements AuthenticationProvider {
    private BaseUserDetailsService baseUserDetailsService;
    private RedisTemplate redisTemplate;
    private PasswordEncoder passwordEncoder;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MobilePwdCodeAuthenticationToken authToken = (MobilePwdCodeAuthenticationToken) authentication;
        SysAuthUser authUser = (SysAuthUser) baseUserDetailsService.loadUserByMobile((String) authToken.getPrincipal());

        if (authUser == null) {
            throw new UsernameNotFoundException("用户不存在或已被冻结");
        }
        String mobile = (String) authToken.getPrincipal();
        String cachedCode = getCacheCode(authToken.getIp());
        String password = (String) authToken.getCredentials();

        String inputCode = authToken.getCode();
        if (StringUtils.isEmpty(cachedCode)) {
            throw new InvalidGrantException("验证码已失效");
        } else if (!inputCode.equals(cachedCode)) {
            throw new InvalidGrantException("验证码错误");

        } else {
            removeCode(mobile);
        }
        if (!passwordEncoder.matches(password, authUser.getPassword())) {
            throw new BadCredentialsException("账户或密码错误");
        }
        //这时候已经认证成功了
        MobilePwdCodeAuthenticationToken authenticationResult = new MobilePwdCodeAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());
        authenticationResult.setDetails(authToken.getDetails());

        return authenticationResult;
    }

    private void removeCode(String username) {
        redisTemplate.delete(RedisKeys.LOGIN_PREFIX + username);
    }

    private String getCacheCode(String ip) {
        String code = (String) redisTemplate.opsForValue().get(RedisKeys.LOGIN_PREFIX + ip);
        return code;
    }


    public void setBaseUserDetailsService(BaseUserDetailsService baseUserDetailsService) {
        this.baseUserDetailsService = baseUserDetailsService;
    }

    public void setRedisTemplate(RedisTemplate jsonRedisTemplate) {
        this.redisTemplate = jsonRedisTemplate;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MobilePwdCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

